Appearance
2776. 转换回调函数为 Promise 函数
ts
type CallbackFn = (
next: (data: number, error: string) => void,
...args: number[]
) => void
type Promisified = (...args: number[]) => Promise<number>
function promisify(fn: CallbackFn): Promisified {
return (...args) =>
new Promise((res, rej) => {
fn((data, err) => {
if (err) rej(err)
res(data)
}, ...args)
})
}
/**
* const asyncFunc = promisify(callback => callback(42));
* asyncFunc().then(console.log); // 42
*/Node.js 的回调约定
在 Promise 成为标准之前,Node.js 生态采用 (err, result) 回调约定——回调的第一个参数是错误,第二个是结果。promisify 就是这种约定到 Promise 的桥梁。
Node.js 内置的 util.promisify 做了完全相同的事,而且处理了更多边界情况(如回调有多个参数时返回对象)。
实现细节
这个实现执行 fn 时传入一个包装后的回调函数。当回调被调用时,检查 err 参数:
- 有 err → reject
- 无 err → resolve(data)
注意 fn 的签名是 (callback, ...args),所以包装后的参数 ...args 会在回调之后传入——这和 Node.js 常见的 (arg1, arg2, callback) 模式有区别。实际使用中需要确认函数签名匹配。
一个已知局限
如果 fn 的回调被多次调用(某些库的行为),Promise 只响应第一次——后续的 resolve/reject 调用会被忽略。这是 Promise 的单次决议特性,也是 promisify 的隐含契约:回调应该只被调用一次。
